/*!
 * \file DataStruct.h
 * \date 2021/01/24 10:57
 *
 * \author wanyzh
 * Contact: yizhao_wan@126.com
 *
 * \brief Global data struct definition. 
 *
 * TODO: long description
 *
 * \note
*/
#pragma once
#define EIGEN_USE_MKL_ALL
#include <vector>
#include <algorithm>
using namespace std;
#include "point.h"
#include <Eigen/Sparse>
#include <Eigen/SparseLU>
#include <Eigen/PardisoSupport>
using namespace Eigen;

/*! A global enum for basis function type */
enum BASIS_TYPE
{
	TWO_DIM_LINEAR,		///<2D linear basis function defined on ELE_3
	TWO_DIM_QUADRATIC,	///<2D quadratic basis function defined on ELE_6
	TWO_DIM_BILINEAR,	///<2D bilinear basis function defined on ELE_4
	TWO_DIM_BIQUADRATIC	///<2D biquadratic basis function defined on ELE_9
};

/*! A global enum for boundary type */
enum BOUNDARY_TYPE
{
	Dirichlet,	///<Dirichlet boundary condition
	Neumann,	///<Neumann boundary condition
	Robin,		///<Robin boundary condition
	Other		///<Other boundary condition
};


/*! A global enum for finite element type */
enum ELE_TYPE {
	ELE_3 = 3,	///<Linear triangle element with 3 nodes
	ELE_4 = 4,	///<Bilinear element with 4 nodes
	ELE_6 = 6,	///<quadratic triangle element with 6 nodes
	ELE_9 = 9	///<Biquadratic element with 9 nodes
};

/*! A global enum for linear equations solve method */
enum SOLVE_METHOD {
	DIREC_SparseLU,				///<SparseLU method in eigen3,Square matrices needed
	DIREC_SimplicialCholesky,	///<Simplicial Cholesky solve method in eigen3,symmetric positive definite (SPD) matrices needed
	DIREC_PardisoLU,			///<Pardiso LU solve method, need extern pardiso library (Pardiso or MKL), Square matrices needed
	DIREC_PardisoLDLT,			///<Pardiso LDLT solve method,need extern pardiso library (Pardiso or MKL),SPD matrices needed
	ITERA_ConjugateGradient,	///<ConjugateGradient solve method in eigen3, SPD matrices needed.
	ITERA_BiCGSTAB				///<BiCGSTAB solve method in eigen3, Square matrices needed.

};

/**
 * @brief One boundary node
 *
 * @details This struct define only one boundary node which contains all the information for that node
 */
struct boundary_node
{
	BOUNDARY_TYPE type;							///<define the boundary type, the value is defined in BOUNDARY_TYPE
	int glo_node_index;							///<define the global index of the boundary node
	vector<double(*)(CPoint, double t)> value;	///<define the boundary value, it is a vector because the unknown of one node may be more than one
	CPoint outer_normal_vector;					///<outer normal vector of the boundary used by Robin and Neumann conditions
	vector<int> mark;							///<define the index in value that should be used.
};

/**
 * @brief One boundary edge
 *
 * @details This struct define only one boundary edge which contains all the information for that edge
 */
struct boundary_edge
{
	BOUNDARY_TYPE type;							///<type of the boundary edge,the value is defined in BOUNDARY_TYPE
	int ele_index;								///<the index of the element which contains the boundary edge
	pair<int,int> p;							///<the global node of the boundary edge
	vector<double(*)(CPoint,double t)> value;	///<define the boundary value of Neumann or Robin, it is defined by a function
	vector<double(*)(CPoint,double t)> r;		///<define the coefficient before the Dirichlet condition


	///@brief Construct function for boundary_edge
	///
	///@param e The element index
	///@param p0 The global node of the boundary edge
	boundary_edge(int e, pair<int,int>p0)
	{ ele_index = e, p = p0; }					
	boundary_edge() {};
	vector<int> mark;							///<define the index in value and r that should be used.
};

typedef Eigen::SparseMatrix<double> SpMat;		///<declares a sparse matrix type of double
typedef Eigen::VectorXd Rsv;					///<declares a right side value type
typedef Eigen::Triplet<double> Tri;				///<declares a triplet to stores the matrix index and values, then convert it to sparse matrix(with high performance)
typedef Eigen::PardisoLU   <SpMat > PLUSolver;	///<declares a Pardiso LU solver
typedef Eigen::PardisoLDLT <SpMat> PLDLTSolver;	///<declares a Pardiso LDLT solver
